using System;
using System.Collections.Generic;
using PropertyExpression.Common;

namespace PropertyExpression.ReactiveRelation
{
    public static partial class Value
    {
        public static IPropertyValue<TTarget> Convert<TSource, TTarget>(
            this IPropertyValue<TSource> propertyValue, Func<TSource, TTarget> func)
        {
            return new PropertyValueConverter<TSource, TTarget>(propertyValue, func);
        }

        private class PropertyValueConverter<TSource, TTarget> : IPropertyValue<TTarget>
        {
            private readonly IPropertyValue<TSource> propertyValue;
            private readonly Func<TSource, TTarget> func;

            public PropertyValueConverter(
                IPropertyValue<TSource> propertyValue, Func<TSource, TTarget> func)
            {
                this.propertyValue = propertyValue;
                this.func = func;
            }

            public IOptionalResult<TTarget> GetValue(IPropertySettor propertySettor, 
                IOneToManyCollectionNewItemProcessor oneToManyCollectionNewItemProcessor)
            {
                return propertyValue.GetValue(propertySettor, oneToManyCollectionNewItemProcessor).Execute(func);
            }

            public IEnumerable<ICell> GetCells()
            {
                return propertyValue.GetCells();
            }

            public IPropertyValue<TProperty> GetPropertyValue<TProperty>(
                IPropertyExpressionProxy<TTarget, TProperty> propertyExpressionProxy)
            {
                return propertyValue.GetPropertyValue(
                    new ExpressionWrapperConverter<TSource, TTarget, TProperty>(
                        propertyExpressionProxy, func
                        )
                    );
            }

            public IEnumerable<object> GetReverseEntities(
                object sender, IPreviousValueProcessor previousValueProcessor)
            {
                return propertyValue.GetReverseEntities(sender, previousValueProcessor);
            }

            public IEnumerable<ICell> GetReverseCells()
            {
                return propertyValue.GetReverseCells();
            }

            public IEnumerable<object> GetReverseEntitiesForCollection(
                object sender, IPreviousValueProcessor previousValueProcessor)
            {
                return propertyValue.GetReverseEntitiesForCollection(sender, previousValueProcessor);
            }

            public IOptionalResult<TResult> ProcessOneToManyCollectionNewItem<TResult>(
                Func<object, TResult> addEntityFunc, 
                Func<object, TResult> removeEntityFunc, 
                Func<TResult> notExistFunc, 
                IPropertySettor propertySettor, 
                IOneToManyCollectionNewItemProcessor oneToManyCollectionNewItemProcessor)
            {
                return propertyValue.ProcessOneToManyCollectionNewItem(
                    addEntityFunc,
                    removeEntityFunc,
                    notExistFunc,
                    propertySettor,
                    oneToManyCollectionNewItemProcessor
                    );
            }
        }
    }
}
